//模拟实现 fopen fwrite fclose 加深对缓冲区的理解
#include "Mystdio.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
_FILE* _fopen(const char* filename,const char* mode)
{
  assert(filename);
  assert(mode);
  //首先判断打开的方式  "w" "a"  "r"
  int m=0;//打开方法
  int fd=-1;//打开后的文件描述符
  if(strcmp(mode,"w")==0)
  {
    m=O_WRONLY|O_CREAT|O_TRUNC;//写、创建、清空
    fd=open(filename,m,MODE);
  }
  else if(strcmp(mode,"a")==0)
  {
    m=O_WRONLY|O_CREAT|O_APPEND;//写、创建、追加
    fd=open(filename,m,MODE);
  }
  else if(strcmp(mode,"r")==0)
  {
    m=O_RDONLY;
    fd=open(filename,m);
  }
  else{
    return NULL;
  }
  if(fd==-1)
  {
    //说明打开文件失败
    return NULL;
  }
  //打开文件成功后创建一个_FILE*指针来维护这个文件
  _FILE* fp=(_FILE*)malloc(sizeof(_FILE));
  if(fp==NULL)
  {
    //申请空间失败
    perror("malloc");
    return NULL;
  }
  //成功
  fp->flag=FFLUSH_ALL;
  fp->fileno=fd;
  fp->pos=0;
  return fp;
}

size_t _fwrite(_FILE*fp,const char*ptr,size_t len)
{
  //写入首先拷贝到缓冲区
  memcpy(&fp->buffer[fp->pos],ptr,len);
  fp->pos+=len;
  //fwrite的时候需要判断是否满足调用write的条件？
  //如果是行刷新，当遇到'\n'立即调用write，如果是全缓冲，缓冲区满了再调用write；如果是立即刷新直接调用write
  
  //判断刷新策略
  if(fp->flag&FFLUSH_LINE)
  {
    if(fp->buffer[fp->pos-1]=='\n')
    {
      write(fp->fileno,fp->buffer,fp->pos);
      fp->pos=0;
    }
  }
  else if(fp->flag&FFLUSH_NOW)
  {
    write(fp->fileno,fp->buffer,fp->pos);
    fp->pos=0;
  }
  else if(fp->flag&FFLUSH_ALL)
  {
    if(fp->pos==SIZE)
    {
      write(fp->fileno,fp->buffer,fp->pos);
      fp->pos=0;
    }
  }
  return len;
  }

void _fflush(_FILE*fp)
{
  //有内容再刷
  if(fp->pos>0)
  write(fp->fileno,fp->buffer,fp->pos);
  fp->pos=0;
}
int _fclose(_FILE*fp)
{
if(fp==NULL)return -1;
 _fflush(fp);
  close(fp->fileno);
  free (fp);
  return 0;
}

